import { defineStore } from 'pinia';
import chatService from '../services/chat';
import type { ChatMessage, Conversation } from '../services/chat';
import { useUserStore } from './user';

interface ChatState {
  conversations: Conversation[];
  activeConversationId: number | null;
  activeConversation: Conversation | null;
  messages: Record<number, ChatMessage[]>;
  unreadCount: number;
  loadingConversations: boolean;
  loadingMessages: boolean;
  error: string | null;
}

export const useChatStore = defineStore('chat', {
  state: (): ChatState => ({
    conversations: [],
    activeConversationId: null,
    activeConversation: null,
    messages: {},
    unreadCount: 0,
    loadingConversations: false,
    loadingMessages: false,
    error: null
  }),

  getters: {
    // Get conversations sorted by last message time
    sortedConversations: (state) => {
      return [...state.conversations].sort((a, b) => {
        const timeA = new Date(a.lastMessageTime).getTime();
        const timeB = new Date(b.lastMessageTime).getTime();
        return timeB - timeA; // Descending order, newest first
      });
    },
    
    // Get messages for a specific conversation
    getMessagesForConversation: (state) => (conversationId: number) => {
      return state.messages[conversationId] || [];
    },
    
    // Get total unread message count
    totalUnreadCount: (state) => {
      return state.unreadCount;
    },
    
    // Check if chat has any errors
    hasError: (state) => !!state.error
  },

  actions: {
    // Initialize chat service
    async initChat() {
      try {
        await chatService.init();
        // Register message callback
        chatService.onMessage(this.handleNewMessage.bind(this));
        
        // Automatically load conversation list
        await this.loadConversations();
        
        // Get total unread message count
        this.fetchUnreadCount();
      } catch (error) {
        console.error('Failed to initialize chat service:', error);
        this.error = 'Failed to initialize chat service';
      }
    },
    
    // Load user's conversation list
    async loadConversations() {
      if (this.loadingConversations) return;
      
      this.loadingConversations = true;
      this.error = null;
      
      try {
        const conversations = await chatService.getConversations();
        this.conversations = conversations;
        this.loadingConversations = false;
      } catch (error) {
        console.error('Failed to load conversation list:', error);
        this.error = 'Failed to load conversation list';
        this.loadingConversations = false;
      }
    },
    
    // Activate specified conversation
    async setActiveConversation(conversationId: number) {
      this.activeConversationId = conversationId;
      
      // Find conversation
      const conversation = this.conversations.find(c => c.id === conversationId);
      if (conversation) {
        this.activeConversation = conversation;
      } else {
        // If not found in the list, may need to reload
        await this.loadConversations();
        const refetchedConversation = this.conversations.find(c => c.id === conversationId);
        this.activeConversation = refetchedConversation || null;
      }
      
      // Load conversation messages
      if (this.activeConversation) {
        await this.loadMessagesForConversation(conversationId);
        
        // Mark conversation as read
        if (this.activeConversation.unreadCount > 0) {
          await this.markConversationAsRead(conversationId);
        }
      }
    },
    
    // Get or create conversation with a specific user
    async getOrCreateConversationWithUser(userId: number) {
      try {
        const conversation = await chatService.getConversationWithUser(userId);
        
        // Add new conversation to the list (if it doesn't exist yet)
        const exists = this.conversations.some(c => c.id === conversation.id);
        if (!exists) {
          this.conversations.push(conversation);
        } else {
          // Update existing conversation
          const index = this.conversations.findIndex(c => c.id === conversation.id);
          if (index !== -1) {
            this.conversations[index] = conversation;
          }
        }
        
        // If there are recent messages, add them to the message list
        if (conversation.recentMessages && conversation.recentMessages.length > 0) {
          this.messages[conversation.id] = conversation.recentMessages;
        }
        
        return conversation;
      } catch (error) {
        console.error('Failed to get user conversation:', error);
        this.error = 'Failed to get user conversation';
        throw error;
      }
    },
    
    // Load messages for a conversation
    async loadMessagesForConversation(conversationId: number, page: number = 0, size: number = 20) {
      if (this.loadingMessages) return;
      
      this.loadingMessages = true;
      this.error = null;
      
      try {
        const messages = await chatService.getMessagesForConversation(conversationId, page, size);
        
        // Initialize or replace message list
        if (page === 0) {
          this.messages[conversationId] = messages;
        } else {
          // Add new messages, avoid duplicates
          const existingIds = new Set(this.messages[conversationId]?.map(m => m.id) || []);
          const newMessages = messages.filter(m => !existingIds.has(m.id));
          
          if (!this.messages[conversationId]) {
            this.messages[conversationId] = [];
          }
          
          this.messages[conversationId] = [...this.messages[conversationId], ...newMessages];
          
          // Sort by send time
          this.messages[conversationId].sort((a, b) => {
            return new Date(a.sentTime).getTime() - new Date(b.sentTime).getTime();
          });
        }
        
        this.loadingMessages = false;
      } catch (error) {
        console.error('Failed to load conversation messages:', error);
        this.error = 'Failed to load conversation messages';
        this.loadingMessages = false;
      }
    },
    
    // Load older messages
    async loadOlderMessages(conversationId: number, messageId: number, size: number = 20) {
      if (this.loadingMessages) return;
      
      this.loadingMessages = true;
      this.error = null;
      
      try {
        const olderMessages = await chatService.getMessagesBeforeId(conversationId, messageId, size);
        
        if (!this.messages[conversationId]) {
          this.messages[conversationId] = [];
        }
        
        // Add new messages, avoid duplicates
        const existingIds = new Set(this.messages[conversationId].map(m => m.id));
        const newMessages = olderMessages.filter(m => !existingIds.has(m.id));
        
        this.messages[conversationId] = [...newMessages, ...this.messages[conversationId]];
        
        // Sort by send time
        this.messages[conversationId].sort((a, b) => {
          return new Date(a.sentTime).getTime() - new Date(b.sentTime).getTime();
        });
        
        this.loadingMessages = false;
        return olderMessages.length;
      } catch (error) {
        console.error('Failed to load older messages:', error);
        this.error = 'Failed to load older messages';
        this.loadingMessages = false;
        return 0;
      }
    },
    
    // Send message
    async sendMessage(recipientId: number, content: string) {
      this.error = null;
      
      try {
        // Check user status before sending message
        const userStore = useUserStore();
        if (!userStore.isLoggedIn || !userStore.userId) {
          throw new Error('User not logged in, cannot send message');
        }
        
        // Send message
        await chatService.sendMessage(recipientId, content);
        
        // If conversation with this recipient already exists
        const conversation = this.conversations.find(c => 
          (c.user1.id === recipientId || c.user2.id === recipientId)
        );
        
        if (conversation) {
          // Note: Since WebSocket message sending doesn't return message content,
          // we don't add the message here. Instead, we let the WebSocket's onMessageReceived
          // callback handle it, which will trigger handleNewMessage.
          // This prevents duplicate message addition.
        } else {
          // If conversation doesn't exist, reload conversation list
          await this.loadConversations();
        }
      } catch (error: any) {
        console.error('Failed to send message:', error);
        
        // Update error message with more detailed feedback
        if (error.response?.data?.message) {
          this.error = error.response.data.message;
        } else if (error.message) {
          this.error = `Send failed: ${error.message}`;
        } else {
          this.error = 'Failed to send message, please try again later';
        }
        
        // If error is specifically about non-existent users, refresh conversation list
        if (error.message && (
          error.message.includes('Sender does not exist') || 
          error.message.includes('Recipient does not exist')
        )) {
          // Reload conversation list, clear potentially invalid users
          await this.loadConversations();
        }
        
        throw error;
      }
    },
    
    // Handle newly received message
    handleNewMessage(message: ChatMessage) {
      // Find corresponding conversation
      const conversationId = message.conversationId;
      const conversation = this.conversations.find(c => c.id === conversationId);
      
      if (conversation) {
        // Update conversation's last message and time
        conversation.lastMessage = message;
        conversation.lastMessageTime = message.sentTime;
        // No longer incrementing unread count
        // conversation.unreadCount += 1;
        
        // Add message to existing conversation
        if (!this.messages[conversationId]) {
          this.messages[conversationId] = [];
        }
        
        // Check if message already exists to avoid duplicates
        const messageExists = this.messages[conversationId].some(m => m.id === message.id);
        if (!messageExists) {
          // Set message as read
          message.read = true;
          this.messages[conversationId].push(message);
          
          // No longer incrementing total unread count
          // this.unreadCount += 1;
          
          // Automatically mark conversation as read
          this.markConversationAsRead(conversationId).catch(error => {
            console.error('Failed to automatically mark conversation as read:', error);
          });
        } else {
          console.log(`Message (ID: ${message.id}) already exists, skipping addition`);
        }
      } else {
        // If conversation doesn't exist, reload conversation list
        this.loadConversations();
      }
    },
    
    // Mark conversation as read
    async markConversationAsRead(conversationId: number) {
      try {
        await chatService.markConversationAsRead(conversationId);
        
        // Update local state
        const conversation = this.conversations.find(c => c.id === conversationId);
        if (conversation) {
          // Reduce total unread count
          this.unreadCount = Math.max(0, this.unreadCount - conversation.unreadCount);
          // Reset conversation unread count
          conversation.unreadCount = 0;
        }
        
        // Mark messages as read
        if (this.messages[conversationId]) {
          this.messages[conversationId] = this.messages[conversationId].map(m => ({
            ...m,
            read: true
          }));
        }
      } catch (error) {
        console.error('Failed to mark conversation as read:', error);
        this.error = 'Failed to mark conversation as read';
      }
    },
    
    // Get unread message count
    async fetchUnreadCount() {
      try {
        const count = await chatService.getUnreadMessageCount();
        this.unreadCount = count;
        return count;
      } catch (error) {
        console.error('Failed to get unread message count:', error);
        return 0;
      }
    },
    
    // Clear chat error
    clearError() {
      this.error = null;
    },
    
    // Clear chat data (e.g., when user logs out)
    clearChatData() {
      this.conversations = [];
      this.activeConversationId = null;
      this.activeConversation = null;
      this.messages = {};
      this.unreadCount = 0;
      this.error = null;
      
      // Disconnect WebSocket connection
      chatService.disconnect();
    }
  }
}); 